/*
-----------------------------------------------------------------------------
This source file is part of SapphireEngine

SapphireEngine is a Framework for Turn Based Strategy games.
For more information see http://code.google.com/p/sapphire-engine/

This program is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.

This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Place - Suite 330, Boston, MA 02111-1307, USA, or go to
http://www.gnu.org/copyleft/lesser.txt.

-----------------------------------------------------------------------------
*/
#include <Ogre.h>
#include <iostream>

//#include "SapphireMemoryManager.h"
#include "Core/CoreManager.h"
#include "Core/Part.h"

using namespace SapphireEngine;
using namespace std;

//Singleton template
template<> CoreManager* Ogre::Singleton<CoreManager>::ms_Singleton = 0;
CoreManager* CoreManager::getSingletonPtr(void)
{
	return ms_Singleton;
}
CoreManager& CoreManager::getSingleton(void)
{  
	assert( ms_Singleton );  return ( *ms_Singleton );  
}
//Constructor
CoreManager::CoreManager():mPartIDNumbering(1)
{
	try 
	{	
		/* Create a connection */
		mDriver = get_driver_instance();
		mConnection = mDriver->connect("tcp://127.0.0.1:3306", "root", "sapir");
		/* Connect to the MySQL test database */
		mConnection->setSchema("Sapphire");

		mStatement = mConnection->createStatement();

		//populate local data
		_getDamageTypes();
		_getTerrainTypes();
		_getTechnologies();
		_getPartTypes();
		_getSubPartTypes();
	}
	catch (sql::SQLException &e)
	{
		cout << "# ERR: SQLException in " << __FILE__;
		cout << "(" << __FUNCTION__ << ") on line " << __LINE__ << endl;
		cout << "# ERR: " << e.what();
		cout << " (MySQL error code: " << e.getErrorCode();
		cout << ", SQLState: " << e.getSQLState() << " )" << endl;
	}
}
//Destructor
CoreManager::~CoreManager()
{
	//clear connection
	if (mStatement)
		delete mStatement;
	if (mConnection)
		delete mConnection;
	for(TechnologyMapIterator itr=mTechnologies.begin();itr!=mTechnologies.end();itr++)
	{
		getMemoryManager()->removePointer(itr->second);
		delete itr->second;
	}	
	for (PartMapIterator itr=mAvailableParts.begin();itr!=mAvailableParts.end();itr++)
	{
		getMemoryManager()->removePointer(itr->second);
		delete itr->second;
	}
	
}

//mySql
void CoreManager::writeSql(Ogre::String str)
{
	try 
	{
		mStatement->execute(str);
		
	}
	catch (sql::SQLException &e)
	{
		cout << "# ERR: SQLException in " << __FILE__;
		cout << "(" << __FUNCTION__ << ") on line " << __LINE__ << endl;
		cout << "# ERR: " << e.what();
		cout << " (MySQL error code: " << e.getErrorCode();
		cout << ", SQLState: " << e.getSQLState() << " )" << endl;
	}
}
sql::ResultSet* CoreManager::readSql(Ogre::String str)
{
	try 
	{
		sql::ResultSet* res = mStatement->executeQuery(str);
		return res;
	}
	catch (sql::SQLException &e)
	{
		cout << "# ERR: SQLException in " << __FILE__;
		cout << "(" << __FUNCTION__ << ") on line " << __LINE__ << endl;
		cout << "# ERR: " << e.what();
		cout << " (MySQL error code: " << e.getErrorCode();
		cout << ", SQLState: " << e.getSQLState() << " )" << endl;
	}
}

sql::Connection* CoreManager::getConnection()
{
	return mConnection;
}
//Terrain
void CoreManager::addTerrainType(Ogre::String name)
{
	mTerrainTypes.insert(name);
}
void CoreManager::removeTerrainType(Ogre::String name)
{
	mTerrainTypes.erase(name);
}
const StringSet* CoreManager::getTerrainTypes()
{
	return &mTerrainTypes;
}

//Damage
void CoreManager::addDamageType(Ogre::String name)
{
	mDamageTypes.insert(name);
}
void CoreManager::removeDamageType(Ogre::String name)
{
	mDamageTypes.erase(name);
}
const StringSet* CoreManager::getDamageTypes()
{
	return &mDamageTypes;
}
 //Technologies
void CoreManager::addTechnology(int id, Ogre::String name, int level)
{
	Technology* tech = new Technology(id,name,level);
	getMemoryManager()->addPointer(tech,"Technology");
	mTechnologies.insert(TechnologyMapItem(id,tech));
}
void CoreManager::removeTechnology(int id)
{
	mTechnologies.erase(id);
}
void CoreManager::setTechnologyLevel(int id, int level)
{
	TechnologyMapIterator itr;
	itr = mTechnologies.find(id);
	itr->second->setLevel(level);
}
const TechnologyMap* CoreManager::getTechnologies()
{
	return &mTechnologies;
}
int CoreManager::getTechnologyID(Ogre::String name)
{
	for (TechnologyMapIterator itr=mTechnologies.begin();itr!=mTechnologies.end();itr++)
	{
		if (itr->second->getName().compare(name)==0)
			return itr->first;
	}
}

//tmp
long CoreManager::getNextPartID()
{
	return mPartIDNumbering++;
}
//Part Types
void CoreManager::addPartType(Ogre::String name)
{
	mPartTypes.insert(name);
}
void CoreManager::removePartType(Ogre::String name)
{
	mPartTypes.erase(name);
}
const StringSet* CoreManager::getPartTypes()
{
	return &mPartTypes;
}

//Part SubTypes
void CoreManager::addPartSubType(Ogre::String name)
{
	mPartSubTypes.insert(name);
}
void CoreManager::removePartSubType(Ogre::String name)
{
	mPartSubTypes.erase(name);
}
const StringSet* CoreManager::getPartSubTypes()
{
	return &mPartSubTypes;
}

//Parts
void CoreManager::addPart(Part *prt)
{
	removePart(prt);
	mAvailableParts.insert(PartMapItem(prt->getID(),prt));
}
void CoreManager::removePart(Part *prt)
{
	mAvailableParts.erase(prt->getID());
}

//Data Population
void CoreManager::_getDamageTypes()
{
	Ogre::String str = "SELECT * FROM damage_types;";
	sql::ResultSet *res = readSql(str);
	while (res->next())
		addDamageType(res->getString(1));
	delete res;
}
void CoreManager::_getTerrainTypes()
{
	Ogre::String str = "SELECT * FROM terrain_types;";
	sql::ResultSet *res = readSql(str);
	while (res->next())
		addTerrainType(res->getString(1));
	delete res;
}
void CoreManager::_getTechnologies()
{
	Ogre::String str = "SELECT * FROM technology;";
	sql::ResultSet *res = readSql(str);
	while (res->next())
		addTechnology(res->getInt(1),res->getString(2),res->getInt(3));
	delete res;
}
void CoreManager::_getPartTypes()
{
	Ogre::String str = "SELECT * FROM part_types;";
	sql::ResultSet *res = readSql(str);
	while (res->next())
		addPartType(res->getString(1));
	delete res;
}
void CoreManager::_getSubPartTypes()
{
	Ogre::String str = "SELECT * FROM part_sub_types;";
	sql::ResultSet *res = readSql(str);
	while (res->next())
		addPartSubType(res->getString(1));
	delete res;
}
